/////////////////////////////////////////////////////
// File Name: dual_port_ram.v
// Author: zeping fan
// mail:   zpfan007@163.com
// Created Time: 2023年09月20日 星期三 20时25分29秒
/////////////////////////////////////////////////////

module dual_port_ram(
rst_n,

clk_w,
wen,
waddr,
wdata,

clk_r,
ren,
raddr,
rdata
);

`include "common_funcs.vh"

parameter   WIDTH       = 256;
parameter   DEPTH       = 16384;
parameter   REG_OUT     = 1'b1;

localparam  ADDR_WIDTH  = log2(DEPTH);


input                       rst_n;
input                       clk_w;
input                       wen;
input   [ADDR_WIDTH-1:0]    waddr;
input   [WIDTH-1:0]         wdata;

input                       clk_r;
input                       ren;
input   [ADDR_WIDTH-1:0]    raddr;
output  [WIDTH-1:0]         rdata;


reg     [WIDTH-1:0]         mem     [DEPTH-1:0];

reg     [WIDTH-1:0]         dout_r;
wire    [WIDTH-1:0]         dout_c;


generate
    genvar i;
    for(i=0;i<DEPTH;i=i+1)begin
        always @(posedge clk_w or negedge rst_n)begin
            if(!rst_n)
                mem[i] <= {WIDTH{1'b0}};
            else if(wen)
                mem[i] <= i==waddr? wdata[WIDTH-1:0] : mem[i];
        end
    end
endgenerate

always @(posedge clk_r or negedge rst_n)begin
    if(!rst_n)
        dout_r[WIDTH-1:0] <= {WIDTH{1'b0}};
    else if(ren)
        dout_r[WIDTH-1:0] <= mem[raddr];
end

assign dout_c[WIDTH-1:0] = ren? mem[raddr] : {WIDTH{1'b0}};

assign rdata[WIDTH-1:0] = REG_OUT? dout_r[WIDTH-1:0] : dout_c[WIDTH-1:0];


addr_violation_chk:
assert property(
disable iff(~rst_n)
@(posedge clk_w or posedge clk_r) ((wen and ren)|->(waddr != raddr)))
else 
    $error("The two addresses should not be equal at the same time, fail time = %0t",$time);

endmodule 

